diff -urN gcc-8.3.0-orig/libsanitizer/asan/asan_fuchsia.cc gcc-8.3.0/libsanitizer/asan/asan_fuchsia.cc
--- gcc-8.3.0-orig/libsanitizer/asan/asan_fuchsia.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/asan/asan_fuchsia.cc	2019-04-24 11:37:30.570191837 +0300
@@ -177,7 +177,7 @@
   SetCurrentThread(thread);
 
   // In lieu of AsanThread::ThreadStart.
-  asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false,
+  asanThreadRegistry().StartThread(thread->tid(), os_id, ThreadType::Regular,
                                    nullptr);
 }
 
diff -urN gcc-8.3.0-orig/libsanitizer/asan/asan_mac.cc gcc-8.3.0/libsanitizer/asan/asan_mac.cc
--- gcc-8.3.0-orig/libsanitizer/asan/asan_mac.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/asan/asan_mac.cc	2019-04-24 11:37:30.571191812 +0300
@@ -160,8 +160,8 @@
     t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
                            parent_tid, stack, /* detached */ true);
     t->Init();
-    asanThreadRegistry().StartThread(t->tid(), GetTid(),
-                                     /* workerthread */ true, 0);
+    asanThreadRegistry().StartThread(t->tid(), GetTid(), ThreadType::Worker,
+                                     nullptr);
     SetCurrentThread(t);
   }
 }
diff -urN gcc-8.3.0-orig/libsanitizer/asan/asan_thread.cc gcc-8.3.0/libsanitizer/asan/asan_thread.cc
--- gcc-8.3.0-orig/libsanitizer/asan/asan_thread.cc	2017-12-05 12:23:25.000000000 +0300
+++ gcc-8.3.0/libsanitizer/asan/asan_thread.cc	2019-04-24 11:37:30.571191812 +0300
@@ -239,8 +239,7 @@
 thread_return_t AsanThread::ThreadStart(
     tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
   Init();
-  asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
-                                   nullptr);
+  asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
   if (signal_thread_is_registered)
     atomic_store(signal_thread_is_registered, 1, memory_order_release);
 
diff -urN gcc-8.3.0-orig/libsanitizer/lsan/lsan_thread.cc gcc-8.3.0/libsanitizer/lsan/lsan_thread.cc
--- gcc-8.3.0-orig/libsanitizer/lsan/lsan_thread.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/lsan/lsan_thread.cc	2019-04-24 11:37:30.571191812 +0300
@@ -75,7 +75,7 @@
                                        /* arg */ nullptr);
 }
 
-void ThreadStart(u32 tid, tid_t os_id, bool workerthread) {
+void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
   OnStartedArgs args;
   uptr stack_size = 0;
   uptr tls_size = 0;
@@ -85,7 +85,7 @@
   args.tls_end = args.tls_begin + tls_size;
   GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
   args.dtls = DTLS_Get();
-  thread_registry->StartThread(tid, os_id, workerthread, &args);
+  thread_registry->StartThread(tid, os_id, thread_type, &args);
 }
 
 void ThreadFinish() {
diff -urN gcc-8.3.0-orig/libsanitizer/lsan/lsan_thread.h gcc-8.3.0/libsanitizer/lsan/lsan_thread.h
--- gcc-8.3.0-orig/libsanitizer/lsan/lsan_thread.h	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/lsan/lsan_thread.h	2019-04-24 11:37:30.571191812 +0300
@@ -43,7 +43,8 @@
 
 void InitializeThreadRegistry();
 
-void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false);
+void ThreadStart(u32 tid, tid_t os_id,
+                 ThreadType thread_type = ThreadType::Regular);
 void ThreadFinish();
 u32 ThreadCreate(u32 tid, uptr uid, bool detached);
 void ThreadJoin(u32 tid);
diff -urN gcc-8.3.0-orig/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc gcc-8.3.0/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
--- gcc-8.3.0-orig/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc	2019-04-24 11:37:30.571191812 +0300
@@ -16,8 +16,8 @@
 
 ThreadContextBase::ThreadContextBase(u32 tid)
     : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
-      status(ThreadStatusInvalid),
-      detached(false), workerthread(false), parent_tid(0), next(0) {
+      status(ThreadStatusInvalid), detached(false),
+      thread_type(ThreadType::Regular), parent_tid(0), next(0) {
   name[0] = '\0';
 }
 
@@ -60,11 +60,11 @@
   OnFinished();
 }
 
-void ThreadContextBase::SetStarted(tid_t _os_id, bool _workerthread,
+void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
                                    void *arg) {
   status = ThreadStatusRunning;
   os_id = _os_id;
-  workerthread = _workerthread;
+  thread_type = _thread_type;
   OnStarted(arg);
 }
 
@@ -281,7 +281,7 @@
   }
 }
 
-void ThreadRegistry::StartThread(u32 tid, tid_t os_id, bool workerthread,
+void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
                                  void *arg) {
   BlockingMutexLock l(&mtx_);
   running_threads_++;
@@ -289,7 +289,7 @@
   ThreadContextBase *tctx = threads_[tid];
   CHECK_NE(tctx, 0);
   CHECK_EQ(ThreadStatusCreated, tctx->status);
-  tctx->SetStarted(os_id, workerthread, arg);
+  tctx->SetStarted(os_id, thread_type, arg);
 }
 
 void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
@@ -316,4 +316,15 @@
   return tctx;
 }
 
+void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
+  BlockingMutexLock l(&mtx_);
+  CHECK_LT(tid, n_contexts_);
+  ThreadContextBase *tctx = threads_[tid];
+  CHECK_NE(tctx, 0);
+  CHECK_NE(tctx->status, ThreadStatusInvalid);
+  CHECK_NE(tctx->status, ThreadStatusDead);
+  CHECK_EQ(tctx->user_id, 0);
+  tctx->user_id = user_id;
+}
+
 }  // namespace __sanitizer
diff -urN gcc-8.3.0-orig/libsanitizer/sanitizer_common/sanitizer_thread_registry.h gcc-8.3.0/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
--- gcc-8.3.0-orig/libsanitizer/sanitizer_common/sanitizer_thread_registry.h	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/sanitizer_common/sanitizer_thread_registry.h	2019-04-24 11:37:30.577191661 +0300
@@ -27,6 +27,12 @@
   ThreadStatusDead       // Joined, but some info is still available.
 };
 
+enum class ThreadType {
+  Regular, // Normal thread
+  Worker,  // macOS Grand Central Dispatch (GCD) worker thread
+  Fiber,   // Fiber
+};
+
 // Generic thread context. Specific sanitizer tools may inherit from it.
 // If thread is dead, context may optionally be reused for a new thread.
 class ThreadContextBase {
@@ -43,7 +49,7 @@
 
   ThreadStatus status;
   bool detached;
-  bool workerthread;
+  ThreadType thread_type;
 
   u32 parent_tid;
   ThreadContextBase *next;  // For storing thread contexts in a list.
@@ -53,7 +59,7 @@
   void SetDead();
   void SetJoined(void *arg);
   void SetFinished();
-  void SetStarted(tid_t _os_id, bool _workerthread, void *arg);
+  void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
                   u32 _parent_tid, void *arg);
   void Reset();
@@ -114,7 +120,8 @@
   void DetachThread(u32 tid, void *arg);
   void JoinThread(u32 tid, void *arg);
   void FinishThread(u32 tid);
-  void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg);
+  void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
+  void SetThreadUserId(u32 tid, uptr user_id);
 
  private:
   const ThreadContextFactory context_factory_;
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors.cc gcc-8.3.0/libsanitizer/tsan/tsan_interceptors.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_interceptors.cc	2019-04-24 11:55:47.970428653 +0300
@@ -201,7 +201,7 @@
 #endif
 
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
-  (!cur_thread()->is_inited)
+  (cur_thread_init(), !cur_thread()->is_inited)
 
 static sigaction_t sigactions[kSigCount];
 
@@ -395,7 +395,7 @@
 
 #if !SANITIZER_ANDROID
 TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return 0;
   // We want to setup the atexit callback even if we are in ignored lib
   // or after fork.
@@ -405,7 +405,7 @@
 #endif
 
 TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return 0;
   SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
   return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso);
@@ -436,7 +436,7 @@
 }
 
 TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return 0;
   SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
   AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx));
@@ -530,6 +530,7 @@
 
 // FIXME: put everything below into a common extern "C" block?
 extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
+  cur_thread_init();
   SetJmp(cur_thread(), sp, mangled_sp);
 }
 
@@ -599,7 +600,7 @@
 
 #if !SANITIZER_MAC
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return InternalAlloc(size);
   void *p = 0;
   {
@@ -616,7 +617,7 @@
 }
 
 TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return InternalCalloc(size, n);
   void *p = 0;
   {
@@ -628,7 +629,7 @@
 }
 
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return InternalRealloc(p, size);
   if (p)
     invoke_free_hook(p);
@@ -643,7 +644,7 @@
 TSAN_INTERCEPTOR(void, free, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return InternalFree(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
@@ -653,7 +654,7 @@
 TSAN_INTERCEPTOR(void, cfree, void *p) {
   if (p == 0)
     return;
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return InternalFree(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(cfree, p);
@@ -883,6 +884,7 @@
   void *param = p->param;
   int tid = 0;
   {
+    cur_thread_init();
     ThreadState *thr = cur_thread();
     // Thread-local state is not initialized yet.
     ScopedIgnoreInterceptors ignore;
@@ -899,7 +901,7 @@
       internal_sched_yield();
     Processor *proc = ProcCreate();
     ProcWire(proc, thr);
-    ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
+    ThreadStart(thr, tid, GetTid(), ThreadType::Regular);
     atomic_store(&p->tid, 0, memory_order_release);
   }
   void *res = callback(param);
@@ -988,6 +990,45 @@
   return res;
 }
 
+TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
+  {
+    SCOPED_INTERCEPTOR_RAW(pthread_exit, retval);
+#if !SANITIZER_MAC && !SANITIZER_ANDROID
+    CHECK_EQ(thr, &cur_thread_placeholder);
+#endif
+  }
+  REAL(pthread_exit)(retval);
+}
+
+#if SANITIZER_LINUX
+TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret);
+  int tid = ThreadTid(thr, pc, (uptr)th);
+  ThreadIgnoreBegin(thr, pc);
+  int res = REAL(pthread_tryjoin_np)(th, ret);
+  ThreadIgnoreEnd(thr, pc);
+  if (res == 0)
+    ThreadJoin(thr, pc, tid);
+  else
+    ThreadNotJoined(thr, pc, tid, (uptr)th);
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
+                 const struct timespec *abstime) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime);
+  int tid = ThreadTid(thr, pc, (uptr)th);
+  ThreadIgnoreBegin(thr, pc);
+  int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
+  ThreadIgnoreEnd(thr, pc);
+  if (res == 0)
+    ThreadJoin(thr, pc, tid);
+  else
+    ThreadNotJoined(thr, pc, tid, (uptr)th);
+  return res;
+}
+#endif
+
 // Problem:
 // NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
 // pthread_cond_t has different size in the different versions.
@@ -1882,6 +1923,7 @@
 
 void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
     my_siginfo_t *info, void *ctx) {
+  cur_thread_init();
   ThreadState *thr = cur_thread();
   ThreadSignalContext *sctx = SigCtx(thr);
   if (sig < 0 || sig >= kSigCount) {
@@ -2046,7 +2088,7 @@
 }
 
 TSAN_INTERCEPTOR(int, fork, int fake) {
-  if (cur_thread()->in_symbolizer)
+  if (in_symbolizer())
     return REAL(fork)(fake);
   SCOPED_INTERCEPTOR_RAW(fork, fake);
   ForkBefore(thr, pc);
@@ -2502,6 +2544,11 @@
   TSAN_INTERCEPT(pthread_create);
   TSAN_INTERCEPT(pthread_join);
   TSAN_INTERCEPT(pthread_detach);
+  TSAN_INTERCEPT(pthread_exit);
+  #if SANITIZER_LINUX
+  TSAN_INTERCEPT(pthread_tryjoin_np);
+  TSAN_INTERCEPT(pthread_timedjoin_np);
+  #endif
 
   TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
   TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors.h gcc-8.3.0/libsanitizer/tsan/tsan_interceptors.h
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors.h	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_interceptors.h	2019-04-24 11:37:30.578191636 +0300
@@ -21,9 +21,17 @@
 
 LibIgnore *libignore();
 
+#if !SANITIZER_GO
+INLINE bool in_symbolizer() {
+  cur_thread_init();
+  return UNLIKELY(cur_thread()->in_symbolizer);
+}
+#endif
+
 }  // namespace __tsan
 
 #define SCOPED_INTERCEPTOR_RAW(func, ...) \
+    cur_thread_init(); \
     ThreadState *thr = cur_thread(); \
     const uptr caller_pc = GET_CALLER_PC(); \
     ScopedInterceptor si(thr, #func, caller_pc); \
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors_mac.cc gcc-8.3.0/libsanitizer/tsan/tsan_interceptors_mac.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_interceptors_mac.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_interceptors_mac.cc	2019-04-24 11:51:44.843579299 +0300
@@ -18,7 +18,9 @@
 #include "tsan_interface.h"
 #include "tsan_interface_ann.h"
 
+#include <errno.h>
 #include <libkern/OSAtomic.h>
+#include <sys/ucontext.h>
 
 #if defined(__has_include) && __has_include(<xpc/xpc.h>)
 #include <xpc/xpc.h>
@@ -26,6 +28,11 @@
 
 typedef long long_t;  // NOLINT
 
+extern "C" {
+int getcontext(ucontext_t *ucp) __attribute__((returns_twice));
+int setcontext(const ucontext_t *ucp);
+}
+
 namespace __tsan {
 
 // The non-barrier versions of OSAtomic* functions are semantically mo_relaxed,
@@ -292,6 +299,31 @@
 
 #endif  // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
 
+TSAN_INTERCEPTOR(int, swapcontext, ucontext_t *oucp, const ucontext_t *ucp) {
+  {
+    SCOPED_INTERCEPTOR_RAW(swapcontext, oucp, ucp);
+  }
+  // Bacause of swapcontext() semantics we have no option but to copy its
+  // impementation here
+  if (!oucp || !ucp) {
+    errno = EINVAL;
+    return -1;
+  }
+  ThreadState *thr = cur_thread();
+  const int UCF_SWAPPED = 0x80000000;
+  oucp->uc_onstack &= ~UCF_SWAPPED;
+  thr->ignore_interceptors++;
+  int ret = getcontext(oucp);
+  if (!(oucp->uc_onstack & UCF_SWAPPED)) {
+    thr->ignore_interceptors--;
+    if (!ret) {
+      oucp->uc_onstack |= UCF_SWAPPED;
+      ret = setcontext(ucp);
+    }
+  }
+  return ret;
+}
+
 // On macOS, libc++ is always linked dynamically, so intercepting works the
 // usual way.
 #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_interface_atomic.cc gcc-8.3.0/libsanitizer/tsan/tsan_interface_atomic.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_interface_atomic.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_interface_atomic.cc	2019-04-24 11:37:30.573191762 +0300
@@ -473,7 +473,7 @@
 
 #define SCOPED_ATOMIC(func, ...) \
     ThreadState *const thr = cur_thread(); \
-    if (thr->ignore_sync || thr->ignore_interceptors) { \
+    if (UNLIKELY(thr->ignore_sync || thr->ignore_interceptors)) { \
       ProcessPendingSignals(thr); \
       return NoTsanAtomic##func(__VA_ARGS__); \
     } \
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_interface.cc gcc-8.3.0/libsanitizer/tsan/tsan_interface.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_interface.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_interface.cc	2019-04-24 11:37:30.578191636 +0300
@@ -23,6 +23,7 @@
 typedef u64 uint64_t;
 
 void __tsan_init() {
+  cur_thread_init();
   Initialize(cur_thread());
 }
 
@@ -122,6 +123,31 @@
   __tsan_unaligned_write8(addr);
   *addr = v;
 }
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_get_current_fiber() {
+  return cur_thread();
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_create_fiber(unsigned flags) {
+  return FiberCreate(cur_thread(), CALLERPC, flags);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_destroy_fiber(void *fiber) {
+  FiberDestroy(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber));
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_switch_to_fiber(void *fiber, unsigned flags) {
+  FiberSwitch(cur_thread(), CALLERPC, static_cast<ThreadState *>(fiber), flags);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_set_fiber_name(void *fiber, const char *name) {
+  ThreadSetName(static_cast<ThreadState *>(fiber), name);
+}
 }  // extern "C"
 
 void __tsan_acquire(void *addr) {
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_malloc_mac.cc gcc-8.3.0/libsanitizer/tsan/tsan_malloc_mac.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_malloc_mac.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_malloc_mac.cc	2019-04-24 11:47:39.066797274 +0300
@@ -26,24 +26,24 @@
   void *p =                                     \
       user_memalign(cur_thread(), StackTrace::GetCurrentPc(), alignment, size)
 #define COMMON_MALLOC_MALLOC(size)                             \
-  if (cur_thread()->in_symbolizer) return InternalAlloc(size); \
+  if (in_symbolizer()) return InternalAlloc(size);             \
   SCOPED_INTERCEPTOR_RAW(malloc, size);                        \
   void *p = user_alloc(thr, pc, size)
 #define COMMON_MALLOC_REALLOC(ptr, size)                              \
-  if (cur_thread()->in_symbolizer) return InternalRealloc(ptr, size); \
+  if (in_symbolizer()) return InternalRealloc(ptr, size);             \
   SCOPED_INTERCEPTOR_RAW(realloc, ptr, size);                         \
   void *p = user_realloc(thr, pc, ptr, size)
 #define COMMON_MALLOC_CALLOC(count, size)                              \
-  if (cur_thread()->in_symbolizer) return InternalCalloc(count, size); \
+  if (in_symbolizer()) return InternalCalloc(count, size);             \
   SCOPED_INTERCEPTOR_RAW(calloc, size, count);                         \
   void *p = user_calloc(thr, pc, size, count)
 #define COMMON_MALLOC_VALLOC(size)                            \
-  if (cur_thread()->in_symbolizer)                            \
+  if (in_symbolizer())                                        \
     return InternalAlloc(size, nullptr, GetPageSizeCached()); \
   SCOPED_INTERCEPTOR_RAW(valloc, size);                       \
   void *p = user_valloc(thr, pc, size)
 #define COMMON_MALLOC_FREE(ptr)                              \
-  if (cur_thread()->in_symbolizer) return InternalFree(ptr); \
+  if (in_symbolizer()) return InternalFree(ptr);             \
   SCOPED_INTERCEPTOR_RAW(free, ptr);                         \
   user_free(thr, pc, ptr)
 #define COMMON_MALLOC_SIZE(ptr) uptr size = user_alloc_usable_size(ptr);
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_new_delete.cc gcc-8.3.0/libsanitizer/tsan/tsan_new_delete.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_new_delete.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_new_delete.cc	2019-04-24 11:37:30.577191661 +0300
@@ -25,7 +25,7 @@
 
 // TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
 #define OPERATOR_NEW_BODY(mangled_name, nothrow) \
-  if (cur_thread()->in_symbolizer) \
+  if (in_symbolizer()) \
     return InternalAlloc(size); \
   void *p = 0; \
   {  \
@@ -62,7 +62,7 @@
 
 #define OPERATOR_DELETE_BODY(mangled_name) \
   if (ptr == 0) return;  \
-  if (cur_thread()->in_symbolizer) \
+  if (in_symbolizer()) \
     return InternalFree(ptr); \
   invoke_free_hook(ptr);  \
   SCOPED_INTERCEPTOR_RAW(mangled_name, ptr);  \
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_platform_linux.cc gcc-8.3.0/libsanitizer/tsan/tsan_platform_linux.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_platform_linux.cc	2018-08-01 21:17:29.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_platform_linux.cc	2019-04-24 11:37:30.578191636 +0300
@@ -382,6 +382,10 @@
   return thr;
 }
 
+void set_cur_thread(ThreadState *thr) {
+  *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
+}
+
 void cur_thread_finalize() {
   __sanitizer_sigset_t emptyset;
   internal_sigfillset(&emptyset);
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_platform_mac.cc gcc-8.3.0/libsanitizer/tsan/tsan_platform_mac.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_platform_mac.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_platform_mac.cc	2019-04-24 11:37:30.579191611 +0300
@@ -72,22 +72,22 @@
 // shadow memory is set up.
 static uptr main_thread_identity = 0;
 ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
+static ThreadState *main_thread_state_loc = (ThreadState *)main_thread_state;
 
-ThreadState **cur_thread_location() {
-  ThreadState **thread_identity = (ThreadState **)pthread_self();
-  return ((uptr)thread_identity == main_thread_identity) ? nullptr
-                                                         : thread_identity;
+static ThreadState **cur_thread_location() {
+  uptr thread_identity = (uptr)pthread_self();
+  if (thread_identity == main_thread_identity || main_thread_identity == 0)
+    return &main_thread_state_loc;
+  return (ThreadState **)MemToShadow(thread_identity);
 }
 
 ThreadState *cur_thread() {
-  ThreadState **thr_state_loc = cur_thread_location();
-  if (thr_state_loc == nullptr || main_thread_identity == 0) {
-    return (ThreadState *)&main_thread_state;
-  }
-  ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
-  ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
-      (uptr *)fake_tls, sizeof(ThreadState));
-  return thr;
+  return (ThreadState *)SignalSafeGetOrAllocate(
+      (uptr *)cur_thread_location(), sizeof(ThreadState));
+}
+
+void set_cur_thread(ThreadState *thr) {
+  *cur_thread_location() = thr;
 }
 
 // TODO(kuba.brecka): This is not async-signal-safe. In particular, we call
@@ -95,14 +95,13 @@
 // handler will try to access the unmapped ThreadState.
 void cur_thread_finalize() {
   ThreadState **thr_state_loc = cur_thread_location();
-  if (thr_state_loc == nullptr) {
+  if (thr_state_loc == &main_thread_state_loc) {
     // Calling dispatch_main() or xpc_main() actually invokes pthread_exit to
     // exit the main thread. Let's keep the main thread's ThreadState.
     return;
   }
-  ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
-  internal_munmap(*fake_tls, sizeof(ThreadState));
-  *fake_tls = nullptr;
+  internal_munmap(*thr_state_loc, sizeof(ThreadState));
+  *thr_state_loc = nullptr;
 }
 #endif
 
@@ -211,7 +210,7 @@
       ThreadState *parent_thread_state = nullptr;  // No parent.
       int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
       CHECK_NE(tid, 0);
-      ThreadStart(thr, tid, GetTid(), /*workerthread*/ true);
+      ThreadStart(thr, tid, GetTid(), ThreadType::Worker);
     }
   } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
     if (thread == pthread_self()) {
@@ -256,11 +255,11 @@
   // The pointer to the ThreadState object is stored in the shadow memory
   // of the tls.
   uptr tls_end = tls_addr + tls_size;
-  ThreadState **thr_state_loc = cur_thread_location();
-  if (thr_state_loc == nullptr) {
+  uptr thread_identity = (uptr)pthread_self();
+  if (thread_identity == main_thread_identity) {
     MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, tls_size);
   } else {
-    uptr thr_state_start = (uptr)thr_state_loc;
+    uptr thr_state_start = thread_identity;
     uptr thr_state_end = thr_state_start + sizeof(uptr);
     CHECK_GE(thr_state_start, tls_addr);
     CHECK_LE(thr_state_start, tls_addr + tls_size);
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_report.cc gcc-8.3.0/libsanitizer/tsan/tsan_report.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_report.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_report.cc	2019-04-24 11:37:30.572191787 +0300
@@ -253,7 +253,7 @@
     Printf(" '%s'", rt->name);
   char thrbuf[kThreadBufSize];
   const char *thread_status = rt->running ? "running" : "finished";
-  if (rt->workerthread) {
+  if (rt->thread_type == ThreadType::Worker) {
     Printf(" (tid=%zu, %s) is a GCD worker thread\n", rt->os_id, thread_status);
     Printf("\n");
     Printf("%s", d.Default());
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_report.h gcc-8.3.0/libsanitizer/tsan/tsan_report.h
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_report.h	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_report.h	2019-04-24 11:50:19.094748679 +0300
@@ -12,6 +12,7 @@
 #define TSAN_REPORT_H
 
 #include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
 #include "tsan_defs.h"
 #include "tsan_vector.h"
 
@@ -90,7 +91,7 @@
   int id;
   tid_t os_id;
   bool running;
-  bool workerthread;
+  ThreadType thread_type;
   char *name;
   u32 parent_tid;
   ReportStack *stack;
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl.cc gcc-8.3.0/libsanitizer/tsan/tsan_rtl.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_rtl.cc	2019-04-24 11:37:30.574191737 +0300
@@ -381,7 +381,7 @@
   // Initialize thread 0.
   int tid = ThreadCreate(thr, 0, 0, true);
   CHECK_EQ(tid, 0);
-  ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
+  ThreadStart(thr, tid, GetTid(), ThreadType::Regular);
 #if TSAN_CONTAINS_UBSAN
   __ubsan::InitAsPlugin();
 #endif
@@ -608,6 +608,7 @@
   // __m128i _mm_move_epi64(__m128i*);
   // _mm_storel_epi64(u64*, __m128i);
   u64 store_word = cur.raw();
+  bool stored = false;
 
   // scan all the shadow values and dispatch to 4 categories:
   // same, replace, candidate and race (see comments below).
@@ -632,16 +633,28 @@
   int idx = 0;
 #include "tsan_update_shadow_word_inl.h"
   idx = 1;
+  if (stored) {
 #include "tsan_update_shadow_word_inl.h"
+  } else {
+#include "tsan_update_shadow_word_inl.h"
+  }
   idx = 2;
+  if (stored) {
+#include "tsan_update_shadow_word_inl.h"
+  } else {
 #include "tsan_update_shadow_word_inl.h"
+  }
   idx = 3;
+  if (stored) {
+#include "tsan_update_shadow_word_inl.h"
+  } else {
 #include "tsan_update_shadow_word_inl.h"
+  }
 #endif
 
   // we did not find any races and had already stored
   // the current access info, so we are done
-  if (LIKELY(store_word == 0))
+  if (LIKELY(stored))
     return;
   // choose a random candidate slot and replace it
   StoreShadow(shadow_mem + (cur.epoch() % kShadowCnt), store_word);
@@ -781,7 +794,7 @@
   }
 #endif
 
-  if (!SANITIZER_GO && *shadow_mem == kShadowRodata) {
+  if (!SANITIZER_GO && !kAccessIsWrite && *shadow_mem == kShadowRodata) {
     // Access to .rodata section, no races here.
     // Measurements show that it can be 10-20% of all memory accesses.
     StatInc(thr, StatMop);
@@ -792,7 +805,7 @@
   }
 
   FastState fast_state = thr->fast_state;
-  if (fast_state.GetIgnoreBit()) {
+  if (UNLIKELY(fast_state.GetIgnoreBit())) {
     StatInc(thr, StatMop);
     StatInc(thr, kAccessIsWrite ? StatMopWrite : StatMopRead);
     StatInc(thr, (StatType)(StatMop1 + kAccessSizeLog));
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl.h gcc-8.3.0/libsanitizer/tsan/tsan_rtl.h
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl.h	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_rtl.h	2019-04-24 11:37:30.579191611 +0300
@@ -380,6 +380,9 @@
   // taken by epoch between synchs.
   // This way we can save one load from tls.
   u64 fast_synch_epoch;
+  // Technically `current` should be a separate THREADLOCAL variable;
+  // but it is placed here in order to share cache line with previous fields.
+  ThreadState* current;
   // This is a slow path flag. On fast path, fast_state.GetIgnoreBit() is read.
   // We do not distinguish beteween ignoring reads and writes
   // for better performance.
@@ -457,12 +460,22 @@
 #if !SANITIZER_GO
 #if SANITIZER_MAC || SANITIZER_ANDROID
 ThreadState *cur_thread();
+void set_cur_thread(ThreadState *thr);
 void cur_thread_finalize();
+INLINE void cur_thread_init() { }
 #else
 __attribute__((tls_model("initial-exec")))
 extern THREADLOCAL char cur_thread_placeholder[];
 INLINE ThreadState *cur_thread() {
-  return reinterpret_cast<ThreadState *>(&cur_thread_placeholder);
+  return reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current;
+}
+INLINE void cur_thread_init() {
+  ThreadState *thr = reinterpret_cast<ThreadState *>(cur_thread_placeholder);
+  if (UNLIKELY(!thr->current))
+    thr->current = thr;
+}
+INLINE void set_cur_thread(ThreadState *thr) {
+  reinterpret_cast<ThreadState *>(cur_thread_placeholder)->current = thr;
 }
 INLINE void cur_thread_finalize() { }
 #endif  // SANITIZER_MAC || SANITIZER_ANDROID
@@ -743,7 +756,8 @@
 void FuncExit(ThreadState *thr);
 
 int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
-void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread);
+void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
+                 ThreadType thread_type);
 void ThreadFinish(ThreadState *thr);
 int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
 void ThreadJoin(ThreadState *thr, uptr pc, int tid);
@@ -752,6 +766,7 @@
 void ThreadSetName(ThreadState *thr, const char *name);
 int ThreadCount(ThreadState *thr);
 void ProcessPendingSignals(ThreadState *thr);
+void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid);
 
 Processor *ProcCreate();
 void ProcDestroy(Processor *proc);
@@ -845,6 +860,16 @@
 }
 #endif
 
+ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags);
+void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber);
+void FiberSwitch(ThreadState *thr, uptr pc, ThreadState *fiber, unsigned flags);
+
+// These need to match __tsan_switch_to_fiber_* flags defined in
+// tsan_interface.h. See documentation there as well.
+enum FiberSwitchFlags {
+  FiberSwitchFlagNoSync = 1 << 0, // __tsan_switch_to_fiber_no_sync
+};
+
 }  // namespace __tsan
 
 #endif  // TSAN_RTL_H
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl_report.cc gcc-8.3.0/libsanitizer/tsan/tsan_rtl_report.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl_report.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_rtl_report.cc	2019-04-24 11:37:30.573191762 +0300
@@ -202,7 +202,7 @@
   rt->running = (tctx->status == ThreadStatusRunning);
   rt->name = internal_strdup(tctx->name);
   rt->parent_tid = tctx->parent_tid;
-  rt->workerthread = tctx->workerthread;
+  rt->thread_type = tctx->thread_type;
   rt->stack = 0;
   rt->stack = SymbolizeStackId(tctx->creation_stack_id);
   if (rt->stack)
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl_thread.cc gcc-8.3.0/libsanitizer/tsan/tsan_rtl_thread.cc
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_rtl_thread.cc	2017-10-19 14:23:59.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_rtl_thread.cc	2019-04-24 11:37:30.579191611 +0300
@@ -238,13 +238,15 @@
   return tid;
 }
 
-void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread) {
+void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
+                 ThreadType thread_type) {
   uptr stk_addr = 0;
   uptr stk_size = 0;
   uptr tls_addr = 0;
   uptr tls_size = 0;
 #if !SANITIZER_GO
-  GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
+  if (thread_type != ThreadType::Fiber)
+    GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
 
   if (tid) {
     if (stk_addr && stk_size)
@@ -256,7 +258,7 @@
 
   ThreadRegistry *tr = ctx->thread_registry;
   OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
-  tr->StartThread(tid, os_id, workerthread, &args);
+  tr->StartThread(tid, os_id, thread_type, &args);
 
   tr->Lock();
   thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
@@ -310,6 +312,12 @@
   ctx->thread_registry->DetachThread(tid, thr);
 }
 
+void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid) {
+  CHECK_GT(tid, 0);
+  CHECK_LT(tid, kMaxTid);
+  ctx->thread_registry->SetThreadUserId(tid, uid);
+}
+
 void ThreadSetName(ThreadState *thr, const char *name) {
   ctx->thread_registry->SetThreadName(thr->tid, name);
 }
@@ -396,4 +404,40 @@
   }
 }
 
+#if !SANITIZER_GO
+void FiberSwitchImpl(ThreadState *from, ThreadState *to) {
+  Processor *proc = from->proc();
+  ProcUnwire(proc, from);
+  ProcWire(proc, to);
+  set_cur_thread(to);
+}
+
+ThreadState *FiberCreate(ThreadState *thr, uptr pc, unsigned flags) {
+  void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadState));
+  ThreadState *fiber = static_cast<ThreadState *>(mem);
+  internal_memset(fiber, 0, sizeof(*fiber));
+  int tid = ThreadCreate(thr, pc, 0, true);
+  FiberSwitchImpl(thr, fiber);
+  ThreadStart(fiber, tid, 0, ThreadType::Fiber);
+  FiberSwitchImpl(fiber, thr);
+  return fiber;
+}
+
+void FiberDestroy(ThreadState *thr, uptr pc, ThreadState *fiber) {
+  FiberSwitchImpl(thr, fiber);
+  ThreadFinish(fiber);
+  FiberSwitchImpl(fiber, thr);
+  internal_free(fiber);
+}
+
+void FiberSwitch(ThreadState *thr, uptr pc,
+                 ThreadState *fiber, unsigned flags) {
+  if (!(flags & FiberSwitchFlagNoSync))
+    Release(thr, pc, (uptr)fiber);
+  FiberSwitchImpl(thr, fiber);
+  if (!(flags & FiberSwitchFlagNoSync))
+    Acquire(fiber, pc, (uptr)fiber);
+}
+#endif
+
 }  // namespace __tsan
diff -urN gcc-8.3.0-orig/libsanitizer/tsan/tsan_update_shadow_word_inl.h gcc-8.3.0/libsanitizer/tsan/tsan_update_shadow_word_inl.h
--- gcc-8.3.0-orig/libsanitizer/tsan/tsan_update_shadow_word_inl.h	2015-10-21 10:32:45.000000000 +0300
+++ gcc-8.3.0/libsanitizer/tsan/tsan_update_shadow_word_inl.h	2019-04-24 11:37:30.574191737 +0300
@@ -16,31 +16,35 @@
   const unsigned kAccessSize = 1 << kAccessSizeLog;
   u64 *sp = &shadow_mem[idx];
   old = LoadShadow(sp);
-  if (old.IsZero()) {
+  if (LIKELY(old.IsZero())) {
     StatInc(thr, StatShadowZero);
-    if (store_word)
+    if (!stored) {
       StoreIfNotYetStored(sp, &store_word);
-    // The above StoreIfNotYetStored could be done unconditionally
-    // and it even shows 4% gain on synthetic benchmarks (r4307).
+      stored = true;
+    }
     break;
   }
   // is the memory access equal to the previous?
-  if (Shadow::Addr0AndSizeAreEqual(cur, old)) {
+  if (LIKELY(Shadow::Addr0AndSizeAreEqual(cur, old))) {
     StatInc(thr, StatShadowSameSize);
     // same thread?
-    if (Shadow::TidsAreEqual(old, cur)) {
+    if (LIKELY(Shadow::TidsAreEqual(old, cur))) {
       StatInc(thr, StatShadowSameThread);
-      if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
+      if (LIKELY(old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))) {
         StoreIfNotYetStored(sp, &store_word);
+        stored = true;
+      }
       break;
     }
     StatInc(thr, StatShadowAnotherThread);
     if (HappensBefore(old, thr)) {
-      if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic))
+      if (old.IsRWWeakerOrEqual(kAccessIsWrite, kIsAtomic)) {
         StoreIfNotYetStored(sp, &store_word);
+        stored = true;
+      }
       break;
     }
-    if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
+    if (LIKELY(old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic)))
       break;
     goto RACE;
   }
@@ -54,7 +58,7 @@
     StatInc(thr, StatShadowAnotherThread);
     if (old.IsBothReadsOrAtomic(kAccessIsWrite, kIsAtomic))
       break;
-    if (HappensBefore(old, thr))
+    if (LIKELY(HappensBefore(old, thr)))
       break;
     goto RACE;
   }
